#ifndef GEOMETRY_DEF

#define GEOMETRY_DEF

#include "globals.h"

#define EPSILON 1.0e-13
#define PointPrec	1.0e-6
#define MyAbs(x) ( (x) >= 0 ? (x) : -(x))
#define Zero(x) (MyAbs(x) < EPSILON)
#define Greater(A,B) ( ((A)-(B)) > EPSILON)
#define Less(A,B) ( ((A)-(B)) < -EPSILON)
#define Equal(A,B) Zero((A)-(B))
#define SignOfaLessb(A,B) (Zero((A)-(B)) ? 0 : ((A) > (B) ? 1 : -1))

#define Coordinate	float
#define RoundPoint(A)	{ \
		(A).x = (Coordinate)((float)(XVal(A))); \
		(A).y = (Coordinate)((float)(YVal(A))); \
		(A).w = 1.0; \
	}

#if 0
		(A).x = (Coordinate)((int)((XVal(A) / PointPrec) + 0.5) * PointPrec); \
		(A).y = (Coordinate)((int)((YVal(A) / PointPrec) + 0.5) * PointPrec); \
		(A).w = 1.0; 
#endif


typedef struct {
	Coordinate	w, x, y;
	}	Pt;

typedef Pt Line;
typedef Pt Vector;

typedef struct {
	Pt		centre, focus;
	Real	focalLength;
	Real	dirSin, dirCos;
	int		sqCoeff;
	Real	scale, offset;
	Line	directrix;
	Pt		scalePt[2];
	}	Parabola;

#define CrossProd1(A,B) ((A)->x * (B)->y - (A)->y * (B)->x)
#define CrossProd2(A,B) ((A)->y * (B)->w - (A)->w * (B)->y)
#define CrossProd3(A,B) ((A)->w * (B)->x - (A)->x * (B)->w)

#define CrossProd(A,B,C) \
	(C)->w = CrossProd1((A),(B)); \
	(C)->x = CrossProd2((A),(B)); \
	(C)->y = CrossProd3((A),(B)); 

#define DotProd(A,B)	((A)->w * (B)->w + (A)->x * (B)->x + (A)->y * (B)->y)

#define Det3(A,B,C)		((A)->w * ((B)->x*(C)->y - (B)->y*(C)->x) - \
						 (A)->x * ((B)->w*(C)->y - (B)->y*(C)->w) + \
						 (A)->y * ((B)->w*(C)->x - (B)->x*(C)->w))
#define LeftSide 1
#define RightSide -1
#define LineSide(ln,pt) (Less(DotProd(ln,pt), 0) ? RightSide : LeftSide)
#define OnTheLine(ln,pt) (Zero(DotProd(ln,pt)) ? True : False)

#define PointAssign(A,B) \
	(A).w = (B).w; \
	(A).x = (B).x; \
	(A).y = (B).y; 

#define PointAssignPtr(A,B) \
	(A)->w = (B)->w; \
	(A)->x = (B)->x; \
	(A)->y = (B)->y; 

#define MidPoint(A,B,C) \
	(C).w = (A).w * (B).w * 2; \
	(C).x = (A).x * (B).w + (A).w * (B).x; \
	(C).y = (A).y * (B).w + (A).w * (B).y; 

#define MidPointPtr(A,B,C) \
	(C)->w = (A)->w * (B)->w * 2; \
	(C)->x = (A)->x * (B)->w + (A)->w * (B)->x; \
	(C)->y = (A)->y * (B)->w + (A)->w * (B)->y; 

#define AddPoints(A,B,C) \
	(C).w = (A).w * (B).w;\
	(C).x = (A).x * (B).w + (A).w * (B).x;\
	(C).y = (A).y * (B).w + (A).w * (B).y;
	
#define SubPoints(A,B,C) \
	(C).w = (A).w * (B).w;\
	(C).x = (A).x * (B).w - (A).w * (B).x;\
	(C).y = (A).y * (B).w - (A).w * (B).y;

#define ScaleVector(Vector, Scale) \
	(Vector).x *= Scale;\
	(Vector).y *= Scale;

#define LineSlope(A) ((A).x / (A).y * -1)
#define LineSlopePtr(A) ((A)->x / (A)->y * -1)

#define LineOf(From,To,Ln) CrossProd(From,To,Ln)
#define IntersectionOf(A,B,C) CrossProd(A,B,C)
#define TranslateLine(Ln, Pt) \
			(Ln)->w = ((Ln)->x * (Pt)->x + (Ln)->y * (Pt)->y) * -1; \
			(Ln)->x = (Ln)->x * (Pt)->w; \
			(Ln)->y = (Ln)->y * (Pt)->w;

#define XVal(A) ((A).x / (A).w)
#define YVal(A) ((A).y / (A).w)

#define XValPtr(A) ((A)->x / (A)->w)
#define YValPtr(A) ((A)->y / (A)->w)

#define PointAtInfinity(A)	((A).w == 0 ? True : False)
#define SamePoint(A,B) (Zero(XValPtr(A)-XValPtr(B)) && \
						Zero(YValPtr(A)-YValPtr(B)))

#ifdef __cplusplus
extern "C" {
#endif

boolean pastSegmentBounds(Pt *point, Pt *start, Pt *end, int *closerEnd);
void perpendicularLine(Pt *point, Line *line, Line *perpenducular);
void ptNearestLine(Pt *point, Line *line, Pt *nearest);
void ptNearestSegment(Pt *point, Pt *start, Pt *end, Pt *nearest);
void createParabola(Pt *focus, Line *directrix, Parabola *para);
void intersectLineParabola(Line *line, Parabola *para, Pt *point1, Pt *point2);
void reorientParabola(Parabola *para, Pt *point1, Pt *point2, 
		boolean trimToScreen);
void drawParabola(int colour, Parabola *para);
Real parabolaParam(Parabola *para, Pt *pt);

#ifdef __cplusplus
}
#endif

#endif
